#============================================================================
import sys
+import os
import threading
import socket
import fcntl
from errno import EAGAIN, EINTR, EWOULDBLOCK
+try:
+ from OpenSSL import SSL
+except ImportError:
+ pass
+
from xen.xend.XendLogging import log
"""General classes to support server and client sockets, without
self.close()
+class SSLSocketServerConnection(SocketServerConnection):
+ """An SSL aware accepted connection to a server.
+
+ As pyOpenSSL SSL.Connection fileno() method just retrieve the file
+ descriptor number for the underlying socket, direct read/write to the file
+ descriptor will result no data encrypted.
+
+ recv2fd() and fd2send() are simple wrappers for functions who need direct
+ read/write to a file descriptor rather than a socket like object.
+
+ To use recv2fd(), you can create a pipe and start a thread to transfer all
+ received data to one end of the pipe, then read from the other end:
+
+ p2cread, p2cwrite = os.pipe()
+ threading.Thread(target=connection.recv2fd, args=(sock, p2cwrite)).start()
+ os.read(p2cread, 1024)
+
+ To use fd2send():
+
+ p2cread, p2cwrite = os.pipe()
+ threading.Thread(target=connection.fd2send, args=(sock, p2cread)).start()
+ os.write(p2cwrite, "data")
+ """
+
+ def __init__(self, sock, protocol_class):
+ SocketServerConnection.__init__(self, sock, protocol_class)
+
+
+ def main(self):
+ try:
+ while True:
+ try:
+ data = self.sock.recv(BUFFER_SIZE)
+ if data == "":
+ break
+ if self.protocol.dataReceived(data):
+ break
+ except socket.error, ex:
+ if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+ break
+ except (SSL.WantReadError, SSL.WantWriteError, \
+ SSL.WantX509LookupError):
+ # The operation did not complete; the same I/O method
+ # should be called again.
+ continue
+ except SSL.ZeroReturnError:
+ # The SSL Connection has been closed.
+ break
+ except SSL.SysCallError, (retval, desc):
+ if ((retval == -1 and desc == "Unexpected EOF")
+ or retval > 0):
+ # The SSL Connection is lost.
+ break
+ log.debug("SSL SysCallError:%d:%s" % (retval, desc))
+ break
+ except SSL.Error, e:
+ # other SSL errors
+ log.debug("SSL Error:%s" % e)
+ break
+ finally:
+ try:
+ self.sock.close()
+ except:
+ pass
+
+
+ def recv2fd(sock, fd):
+ try:
+ while True:
+ try:
+ data = sock.recv(BUFFER_SIZE)
+ if data == "":
+ break
+ count = 0
+ while count < len(data):
+ try:
+ nbytes = os.write(fd, data[count:])
+ count += nbytes
+ except os.error, ex:
+ if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+ raise
+ except socket.error, ex:
+ if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+ break
+ except (SSL.WantReadError, SSL.WantWriteError, \
+ SSL.WantX509LookupError):
+ # The operation did not complete; the same I/O method
+ # should be called again.
+ continue
+ except SSL.ZeroReturnError:
+ # The SSL Connection has been closed.
+ break
+ except SSL.SysCallError, (retval, desc):
+ if ((retval == -1 and desc == "Unexpected EOF")
+ or retval > 0):
+ # The SSL Connection is lost.
+ break
+ log.debug("SSL SysCallError:%d:%s" % (retval, desc))
+ break
+ except SSL.Error, e:
+ # other SSL errors
+ log.debug("SSL Error:%s" % e)
+ break
+ finally:
+ try:
+ sock.close()
+ os.close(fd)
+ except:
+ pass
+
+ recv2fd = staticmethod(recv2fd)
+
+ def fd2send(sock, fd):
+ try:
+ while True:
+ try:
+ data = os.read(fd, BUFFER_SIZE)
+ if data == "":
+ break
+ count = 0
+ while count < len(data):
+ try:
+ nbytes = sock.send(data[count:])
+ count += nbytes
+ except socket.error, ex:
+ if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+ raise
+ except (SSL.WantReadError, SSL.WantWriteError, \
+ SSL.WantX509LookupError):
+ # The operation did not complete; the same I/O method
+ # should be called again.
+ continue
+ except SSL.ZeroReturnError:
+ # The SSL Connection has been closed.
+ raise
+ except SSL.SysCallError, (retval, desc):
+ if not (retval == -1 and data == ""):
+ # errors when writing empty strings are expected
+ # and can be ignored
+ log.debug("SSL SysCallError:%d:%s" % (retval, desc))
+ raise
+ except SSL.Error, e:
+ # other SSL errors
+ log.debug("SSL Error:%s" % e)
+ raise
+ except os.error, ex:
+ if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+ break
+ finally:
+ try:
+ sock.close()
+ os.close(fd)
+ except:
+ pass
+
+ fd2send = staticmethod(fd2send)
+
def hostAllowed(addrport, hosts_allowed):
if hosts_allowed is None:
return True
if port == 0:
port = xoptions.get_xend_relocation_port()
- try:
- tls = xoptions.get_xend_relocation_tls()
- if tls:
- from OpenSSL import SSL
+ tls = xoptions.get_xend_relocation_tls()
+ if tls:
+ from OpenSSL import SSL
+ from xen.web import connection
+ try:
ctx = SSL.Context(SSL.SSLv23_METHOD)
- sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
+ sock = SSL.Connection(ctx,
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sock.set_connect_state()
- else:
+ sock.connect((dst, port))
+ sock.send("sslreceive\n")
+ sock.recv(80)
+ except SSL.Error, err:
+ raise XendError("SSL error: %s" % err)
+ except socket.error, err:
+ raise XendError("can't connect: %s" % err)
+
+ p2cread, p2cwrite = os.pipe()
+ threading.Thread(target=connection.SSLSocketServerConnection.fd2send,
+ args=(sock, p2cread)).start()
+
+ try:
+ XendCheckpoint.save(p2cwrite, dominfo, True, live, dst,
+ node=node)
+ finally:
+ sock.shutdown()
+ sock.close()
+
+ os.close(p2cread)
+ os.close(p2cwrite)
+ else:
+ try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.connect((dst, port))
- except socket.error, err:
- raise XendError("can't connect: %s" % err[1])
+ # When connecting to our ssl enabled relocation server using a
+ # plain socket, send will success but recv will block. Add a
+ # 30 seconds timeout to raise a socket.timeout exception to
+ # inform the client.
+ sock.settimeout(30.0)
+ sock.connect((dst, port))
+ sock.send("receive\n")
+ sock.recv(80)
+ sock.settimeout(None)
+ except socket.error, err:
+ raise XendError("can't connect: %s" % err)
- sock.send("receive\n")
- sock.recv(80)
- try:
- XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst, node=node)
- finally:
- sock.close()
+ try:
+ XendCheckpoint.save(sock.fileno(), dominfo, True, live,
+ dst, node=node)
+ finally:
+ sock.close()
def domain_save(self, domid, dst, checkpoint=False):
"""Start saving a domain to file.
#============================================================================
import re
+import os
import sys
import StringIO
+import threading
-from xen.web import protocol, tcp, unix
+from xen.web import protocol, tcp, unix, connection
from xen.xend import sxp
from xen.xend import XendDomain
log.error(name + ": no transport")
raise XendError(name + ": no transport")
+ def op_sslreceive(self, name, _):
+ if self.transport:
+ self.send_reply(["ready", name])
+ p2cread, p2cwrite = os.pipe()
+ threading.Thread(target=connection.SSLSocketServerConnection.recv2fd,
+ args=(self.transport.sock, p2cwrite)).start()
+ try:
+ XendDomain.instance().domain_restore_fd(p2cread,
+ relocating=True)
+ except:
+ os.close(p2cread)
+ os.close(p2cwrite)
+ self.send_error()
+ self.close()
+ else:
+ log.error(name + ": no transport")
+ raise XendError(name + ": no transport")
+
def listenRelocation():
xoptions = XendOptions.instance()